package com.example.myproject.redis.distributionlock.jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Collections;

//参考网站https://www.cnblogs.com/demingblog/p/9542124.html
public class JedisLockUtil {
    private static int expiredNx = 5;

    public static boolean lock(String key,String lockValue,int expire){
        if(null == key){
            return false;
        }
        try {
            Jedis jedis = getJedisPool().getResource();
            String res = jedis.set(key,lockValue,"NX","EX",expire);
            jedis.close();
            return res!=null && res.equals("OK");
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取一个分布式锁 , 超时则返回失败
     * @param key           锁的key
     * @param lockValue     锁的value
     * @param waitTimeout       获取锁的等待时间，单位为 秒
     * @return              获锁成功 - true | 获锁失败 - false
     */
    public static boolean tryLock(String key,String lockValue,int waitTimeout,int expire){
        final long start = System.currentTimeMillis();
        if(waitTimeout > expiredNx) {
            waitTimeout = expiredNx;
        }
        final long end = start + waitTimeout * 1000;
        boolean res = false; // 默认返回失败
        while(!(res = lock(key,lockValue,expire))){ // 调用了上面的 lock方法
            if(System.currentTimeMillis() > end) {
                break;
            }
        }
        return res;
    }

    private static final Long lockReleaseOK = 1L;
    static String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";// lua脚本，用来释放分布式锁

    public static boolean releaseLock(String key ,String lockValue){
        if(key == null || lockValue == null) {
            return false;
        }
        try {
            Jedis jedis = getJedisPool().getResource();
            Object res =jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(lockValue));
            jedis.close();
            return res!=null && res.equals(lockReleaseOK);
        } catch (Exception e) {
            return false;
        }
    }
    private static JedisPool getJedisPool(){
        JedisPool jedisPool = new JedisPool();
        return  jedisPool;
    }


}
